package com.xunk.scene.util;


import com.xunk.common.core.text.Convert;
import com.xunk.scene.constant.SceneConstant;
import com.xunk.scene.domain.TaskSchedule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;

import java.util.Arrays;
import java.util.List;

/**
 * @author tangguangyuan
 * @ClassName: CronUtil
 * @Description: Cron表达式工具类
 * 按日、按周、按月
 * 目前支持三种常用的cron表达式
 * @date 2021/4/21
 */
public class CronUtil {

    private static final Logger log = LoggerFactory.getLogger(CronUtil.class);

    /**
     * 构建定时任务的文字描述
     *
     * @param taskSchedule
     * @return
     */
    public static String buildCronDescription(TaskSchedule taskSchedule) {
        StringBuffer cronDesc = new StringBuffer();

        if (ObjectUtils.isEmpty(taskSchedule.getJobType())) {
            System.out.println("执行周期未配置");//执行周期未配置
        }

        //校验任务类正确性
        doCheck(taskSchedule);

        Integer[] days;

        switch (taskSchedule.getJobType()) {
            //按日
            case SceneConstant.day:
                cronDesc.append("每天");
                break;
            //法定工作日
            case SceneConstant.workDate:
                cronDesc.append("每周一到周五");
                break;

            //按月
            case SceneConstant.month:
                cronDesc.append("每月");
                //一个月中的哪几天
                days = taskSchedule.getDayOfMonths();
                Arrays.sort(days);
                for (int i = 0; i < days.length; i++) {
                    if (i == 0) {
                        cronDesc.append(days[i]);
                    } else {
                        cronDesc.append(",").append(days[i]);
                    }
                }
                cronDesc.append("号");
                break;
            //按周
            case SceneConstant.week:
                cronDesc.append("每周");
                //周
                Integer[] weeks = taskSchedule.getDayOfWeeks();
                for (int i = 0; i < weeks.length; i++) {
                    if (i == 0) {
                        cronDesc.append(weeks[i]);
                    } else {
                        cronDesc.append(",").append(weeks[i]);
                    }
                }
                break;

            //指定日期
            case SceneConstant.date:
                cronDesc.append(taskSchedule.getMonth()).append("月");
                //日
                days = taskSchedule.getDayOfMonths();

                for (int i = 0; i < days.length; i++) {
                    if (i == 0) {
                        cronDesc.append(days[i]).append("日");
                    }
                }
                break;
            //周末
            case SceneConstant.weekend:
                cronDesc.append("每周末");
                break;
        }

        if (cronDesc.length() > 0) {
            cronDesc.append("的");
        }
        //小时
        cronDesc.append(taskSchedule.getHour()).append("点");
        //分
        cronDesc.append(taskSchedule.getMinute()).append("分");
        return cronDesc.toString();
    }

    /**
     * 方法摘要：构建Cron表达式
     *
     * @param taskSchedule
     * @return String
     */
    public static String buildCronExpression(TaskSchedule taskSchedule) {
        StringBuffer cronExp = new StringBuffer("");

        if (null == taskSchedule.getJobType()) {
            System.out.println("执行周期未配置");//执行周期未配置
        }

        //校验任务类正确性
        doCheck(taskSchedule);

        //秒
        cronExp.append("00").append(" ");
        //分
        cronExp.append(taskSchedule.getMinute()).append(" ");
        //小时
        cronExp.append(taskSchedule.getHour()).append(" ");

        Integer[] days;

        switch (taskSchedule.getJobType()) {
            //按日
            case SceneConstant.day:
                cronExp.append("* ");//日
                cronExp.append("* ");//月
                cronExp.append("? ");//周
                cronExp.append("*");//年
                break;
            //法定工作日
            case SceneConstant.workDate:
                cronExp.append("? ");//日
                cronExp.append("* ");//月
                cronExp.append("1,2,3,4,5 ");//周
                cronExp.append("*");//年
                break;

            //按月
            case SceneConstant.month:
                //一个月中的哪几天
                days = taskSchedule.getDayOfMonths();
                for (int i = 0; i < days.length; i++) {
                    if (i == 0) {
                        cronExp.append(days[i]);
                    } else {
                        cronExp.append(",").append(days[i]);
                    }
                }
                //月份
                cronExp.append(" * ");
                //周
                cronExp.append("? ");
                //年
                cronExp.append("*");
                break;
            //按周
            case SceneConstant.week:
                //一个月中第几天
                cronExp.append("? ");
                //月份
                cronExp.append("* ");
                //周
                Integer[] weeks = taskSchedule.getDayOfWeeks();
                for (int i = 0; i < weeks.length; i++) {
                    if (i == 0) {
                        cronExp.append(weeks[i]);
                    } else {
                        cronExp.append(",").append(weeks[i]);
                    }
                }
                //年
                cronExp.append(" *");
                break;

            //指定日期
            case SceneConstant.date:
                //日
                days = taskSchedule.getDayOfMonths();

                for (int i = 0; i < days.length; i++) {
                    if (i == 0) {
                        cronExp.append(days[i]);
                    }
                }

                cronExp.append(" ");
                //月
                cronExp.append(taskSchedule.getMonth()).append(" ");
                //周
                cronExp.append("?").append(" ");
                //年
                cronExp.append("*");
                break;
            //周末
            case SceneConstant.weekend:
                cronExp.append("? ");//日
                cronExp.append("* ");//月
                cronExp.append("6,7 ");//周
                cronExp.append("*");//年
                break;
        }

        return cronExp.toString();
    }

    /**
     * cron表达式生成taskSchedule类
     */
    public static TaskSchedule buildTaskSchedule(String cronExp, String jobType, Integer id) {

        TaskSchedule taskSchedule = new TaskSchedule();
        taskSchedule.setId(id);
        List<String> items = Arrays.asList(cronExp.split(" "));

        //分
        taskSchedule.setMinute(items.get(1));
        //时
        taskSchedule.setHour(items.get(2));

        Integer[] dayOfWeek;
        Integer[] dayOfMonth;

        /**
         * 根据作业类型生成TaskSchedule，
         */
        taskSchedule.setJobType(jobType);

        switch (jobType) {
            case SceneConstant.day:
                //每天执行时，无需其他参数
                break;
            case SceneConstant.week:
                //按周执行时，需填写一周内哪几天
                dayOfWeek = Convert.toIntArray(",", items.get(5));
                taskSchedule.setDayOfWeeks(dayOfWeek);
                break;
            case SceneConstant.month:
                dayOfMonth = Convert.toIntArray(",", items.get(3));
                taskSchedule.setDayOfMonths(dayOfMonth);
                break;
            case SceneConstant.date:
                dayOfWeek = Convert.toIntArray(",", items.get(5));
                taskSchedule.setDayOfWeeks(dayOfWeek);
                taskSchedule.setMonth(Integer.valueOf(items.get(4)));
                break;
            case SceneConstant.workDate:
                //工作执行时，无需其他参数，定时任务拦截器判断当前日期是否为工作日
                break;
            case SceneConstant.weekend:
                break;
            default:
                log.error(String.format("作业类型%s错误,请确认", jobType));
        }


        return taskSchedule;
    }

    //校验任务类 参数正确性
    public static void doCheck(TaskSchedule taskSchedule) {
        String jobType = taskSchedule.getJobType();

        if (null == taskSchedule.getMinute() || null == taskSchedule.getHour()) {
            throw new RuntimeException("时或分参数未配置");
        }

        switch (jobType) {
            case SceneConstant.day:
                //每日，出分 时外 无需校验
                break;
            case SceneConstant.week:
                //按周执行时，需填写一周内哪几天
                if (taskSchedule.getDayOfWeeks().length == 0)
                    throw new RuntimeException("未指定一周内哪些天执行场景");
                break;
            case SceneConstant.month:
                if (taskSchedule.getDayOfMonths().length == 0)
                    throw new RuntimeException("未指定一月内哪些天执行场景");
                break;
            case SceneConstant.date:
                if (taskSchedule.getDayOfMonths().length == 0)
                    throw new RuntimeException("未指定执行日");
                Integer month = taskSchedule.getMonth();
                if (month == null)
                    throw new RuntimeException("未指定执行月");
                break;
            case SceneConstant.workDate:
                break;
            case SceneConstant.weekend:
                break;
            default:
                throw new RuntimeException(String.format("作业类型%s错误,请确认", jobType));
        }
    }


    /**
     *
     *方法摘要：生成定时的详细描述
     *@param  taskSchedule
     *@return String
     */   
    /*public static String buildDescription(TaskSchedule taskSchedule){
        StringBuffer description = new StringBuffer("");   
        //计划执行开始时间   
//      Date startTime = taskScheduleModel.getScheduleStartTime();   
             
        if (null != taskSchedule.getMinute() && null != taskSchedule.getHour()) {
            //按每天   
            if(taskSchedule.getJobType().intValue() == 1){
                description.append("每天");   
                description.append(taskSchedule.getHour()).append("时");
                description.append(taskSchedule.getMinute()).append("分");
                description.append("执行");
            }   
                 
            //按每周   
            else if(taskSchedule.getJobType().intValue() == 3){
                if(taskSchedule.getDayOfWeeks() != null && taskSchedule.getDayOfWeeks().length > 0) {
                    String days = ""; 
                    for(int i : taskSchedule.getDayOfWeeks()) {
                        days += "周" + i; 
                    } 
                    description.append("每周的").append(days).append(" ");   
                }   
                if (null != taskSchedule.getMinute() && null != taskSchedule.getHour()) {
                    description.append(",");    
                    description.append(taskSchedule.getHour()).append("时");
                    description.append(taskSchedule.getMinute()).append("分");
                }
                description.append("执行");   
            }   
                 
            //按每月   
            else if(taskSchedule.getJobType().intValue() == 2){
                //选择月份   
                if(taskSchedule.getDayOfMonths() != null && taskSchedule.getDayOfMonths().length > 0) {
                    String days = ""; 
                    for(int i : taskSchedule.getDayOfMonths()) {
                        days += i + "号"; 
                    } 
                    description.append("每月的").append(days).append(" ");   
                }     
                description.append(taskSchedule.getHour()).append("时");
                description.append(taskSchedule.getMinute()).append("分");
                description.append("执行");
            }   
                 
        }   
        return description.toString();   
    }*/

    //参考例子 
   /* public static void main(String[] args) {
        //执行时间：每天的12时12分12秒 start 
        TaskSchedule taskSchedule = new TaskSchedule();
        taskSchedule.setJobType(1);//按每天
        Integer hour = 12; //时 
        Integer minute = 12; //分 
        taskSchedule.setHour(hour);
        taskSchedule.setMinute(minute);
        String cropExp = buildCronExpression(taskSchedule);
        System.out.println(cropExp + ":" + buildDescription(taskSchedule));
        //执行时间：每天的12时12分12秒 end 
           
        taskSchedule.setJobType(3);//每周的哪几天执行
        Integer[] dayOfWeeks = new Integer[3]; 
        dayOfWeeks[0] = 1; 
        dayOfWeeks[1] = 2; 
        dayOfWeeks[2] = 3; 
        taskSchedule.setDayOfWeeks(dayOfWeeks);
        cropExp = buildCronExpression(taskSchedule);
        System.out.println(cropExp + ":" + buildDescription(taskSchedule));
           
        taskSchedule.setJobType(2);//每月的哪几天执行
        Integer[] dayOfMonths = new Integer[3]; 
        dayOfMonths[0] = 1; 
        dayOfMonths[1] = 21; 
        dayOfMonths[2] = 13; 
        taskSchedule.setDayOfMonths(dayOfMonths);
        cropExp = buildCronExpression(taskSchedule);
        System.out.println(cropExp + ":" + buildDescription(taskSchedule));
           
    } */
} 